home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume4 / loadav < prev    next >
Encoding:
Internet Message Format  |  1986-11-30  |  11.4 KB

  1. Subject: Routines to check the load average
  2. Newsgroups: mod.sources
  3. Approved: jpn@panda.UUCP
  4.  
  5. Mod.sources:  Volume 4, Issue 78
  6. Submitted by: genrad!decvax!trwrb!jsb
  7.  
  8. Here are some routines I wrote that will allow any program
  9. to check on the load average without themselves having to have
  10. permission to read /dev/kmem.  
  11.  
  12.     John Bien
  13.     decvax!trwrb!jsb
  14.  
  15. ------------------------ Cut Here ---------------------------
  16. #! /bin/sh
  17. # This is a shell archive, meaning:
  18. # 1. Remove everything above the #! /bin/sh line.
  19. # 2. Save the resulting text in a file.
  20. # 3. Execute the file with /bin/sh (not csh) to create the files:
  21. #    README
  22. #    Makefile
  23. #    example.c
  24. #    getld.c
  25. #    getload.3
  26. #    getload.c
  27. #    loadstuff.h
  28. #    u_getloads.c
  29. # This archive created: Fri Apr 25 07:20:24 1986
  30. export PATH; PATH=/bin:$PATH
  31. echo shar: extracting "'README'" '(1513 characters)'
  32. if test -f 'README'
  33. then
  34.     echo shar: will not over-write existing file "'README'"
  35. else
  36. cat << \SHAR_EOF > 'README'
  37. Here are 2 library funtions that will allow non-setuid (or setgid) 
  38. functions to check the load average.  They are:
  39.  
  40. getload():    A fast routine which will return only
  41.           the 1, 5, or 15 minute average.  It only returns
  42.           1 decimal place of accuracy (ie 3.1 instead of 3.08) and
  43.           will only tell load averages below 25.0
  44.           It requires a program installed on the system called
  45.           "getld".  This setgid program reads /dev/kmem and
  46.           exits with information we need.
  47. ugetloads():  A much slower routine that will return all 3 load
  48.           averages via an array passed to it.  It just
  49.           runs uptime(1) and captures the information it needs from
  50.           there not requiring the external program getld.
  51.  
  52.  
  53. If getload() is usable (ie you install the program "getld")
  54. it is much faster than ugetloads() and can be called 3 times
  55. (to get the 3 load averages) in much less time than ugetloads()
  56. can be called once.  The speed of getload() lies in the fact that "getld"
  57. exits() with the load average we want instead of printing
  58. it. This way getload() doesn't have to open a pipe to read what "getld" might
  59. otherwise print, it just has to look at the high byte of the exit status.
  60.  
  61. The routine ugetloads() allows anyone to get the load averages
  62. without any extra programs on the system.  It's good if you don't happen
  63. to be super-user and can let "getld" read /dev/kmem.
  64.  
  65. A sample program example.c demonstrates the use of these routines.
  66.  
  67.     John Bien
  68.     {ihnp4 | ucbvax | decvax}!trwrb!jsb
  69.  
  70. SHAR_EOF
  71. if test 1513 -ne "`wc -c < 'README'`"
  72. then
  73.     echo shar: error transmitting "'README'" '(should have been 1513 characters)'
  74. fi
  75. fi
  76. echo shar: extracting "'Makefile'" '(880 characters)'
  77. if test -f 'Makefile'
  78. then
  79.     echo shar: will not over-write existing file "'Makefile'"
  80. else
  81. cat << \SHAR_EOF > 'Makefile'
  82. # Makefile for load average routines.
  83. # John Bien
  84.  
  85. # Define -DBSD41 if you are running 4.1 (only used in ugetload())
  86. CFLAGS = -O
  87. CC = cc
  88. RANLIB = ranlib
  89. LIBNAME = libload.a
  90. LIBDIR = /usr/local/lib
  91.  
  92. # PROGDIR is where the setgid program getld will reside
  93. PROGDIR = /usr/local/lib
  94.  
  95. # MEMGRP = the group that is allowed to read /dev/kmem
  96. MEMGRP = sys
  97.  
  98. CFILES = getload.c u_getloads.c
  99. OFILES = getload.o u_getloads.o
  100.  
  101. all: $(LIBNAME) getld
  102.  
  103. $(LIBNAME): $(OFILES)
  104.     ar rc $(LIBNAME) $(OFILES)
  105.     $(RANLIB) $(LIBNAME)
  106.  
  107. getld: getld.c
  108.     $(CC) $(CFLAGS) -o getld getld.c
  109.  
  110. example: 
  111.     $(CC) $(CFLAGS) -o example example.c $(LIBNAME)
  112.  
  113. install: $(LIBNAME) getld
  114.     cp $(LIBNAME) $(LIBDIR)
  115.     $(RANLIB) $(LIBDIR)/$(LIBNAME)
  116.     cp getld $(PROGDIR)
  117.     chgrp $(MEMGRP) $(PROGDIR)/getld
  118.     chmod 2111 $(PROGDIR)/getld
  119.  
  120. shar:
  121.     shar README getload.3 Makefile getld.c loadstuff.h \
  122.         $(CFILES) example.c > Shar
  123. SHAR_EOF
  124. if test 880 -ne "`wc -c < 'Makefile'`"
  125. then
  126.     echo shar: error transmitting "'Makefile'" '(should have been 880 characters)'
  127. fi
  128. fi
  129. echo shar: extracting "'example.c'" '(874 characters)'
  130. if test -f 'example.c'
  131. then
  132.     echo shar: will not over-write existing file "'example.c'"
  133. else
  134. cat << \SHAR_EOF > 'example.c'
  135. main()
  136. {
  137.     float getload(), average;
  138.     float aves[3];
  139.     
  140.     average = getload(1);
  141.     if((int)average == -99)
  142.     puts("1 minute average is greater than 25.0");
  143.     else if(average < 0)
  144.     puts("Error using getload");
  145.     else
  146.         printf("One minute average is %.1f\n",average);
  147.  
  148.     average = getload(5);
  149.     if((int)average == -99)
  150.     puts("5 minute average is greater than 25.0");
  151.     else if(average < 0)
  152.     puts("Error using getload");
  153.     else
  154.         printf("Five minute average is %.1f\n",average);
  155.  
  156.     average = getload(15);
  157.     if((int)average == -99)
  158.     puts("15 minute average is greater than 25.0");
  159.     else if(average < 0)
  160.     puts("Error using getload");
  161.     else
  162.         printf("Fifteen minute average is %.1f\n",average);
  163.  
  164.     ugetloads(aves);
  165.  
  166.     printf("And using ugetloads, the load averages are: %.2f, %.2f, %.2f\n",
  167.         aves[0], aves[1], aves[2]); 
  168. }
  169. SHAR_EOF
  170. if test 874 -ne "`wc -c < 'example.c'`"
  171. then
  172.     echo shar: error transmitting "'example.c'" '(should have been 874 characters)'
  173. fi
  174. fi
  175. echo shar: extracting "'getld.c'" '(1511 characters)'
  176. if test -f 'getld.c'
  177. then
  178.     echo shar: will not over-write existing file "'getld.c'"
  179. else
  180. cat << \SHAR_EOF > 'getld.c'
  181. /* getld.c
  182.  * This program must be setgid to memory (or whoever is allowed
  183.  * to read /dev/kmem).  It exits with with the load average, or
  184.  * a negative number to indicate an error.
  185.  * It serves primarily to be called by the library routine
  186.  * getload();
  187.  */
  188.  
  189. #include <stdio.h>
  190. #include <nlist.h>
  191. #include "loadstuff.h"
  192.  
  193. struct nlist avenrun[] =
  194. {
  195.     {    "_avenrun"    },
  196.     {        0        }
  197. };
  198.  
  199. main(argc,argv)
  200. int argc;
  201. char **argv;
  202. {
  203.  
  204.     register int kmem, whatave, returnave;
  205.     double avg[3];
  206.  
  207.     if((kmem = open("/dev/kmem", 0)) < 0)
  208.     exit(NOKMEM);
  209.  
  210.     nlist(NAMELIST, avenrun);    /* Find where our kernel keeps it */
  211.     if(avenrun[0].n_type == 0)
  212.     exit(NONAMELST);
  213.  
  214.     whatave = atoi(argv[1]);
  215.     --whatave;
  216.     if(whatave == 4) whatave = 1;
  217.     if(whatave == 14) whatave = 2;
  218.     
  219.     if(whatave <0 || whatave > 2)
  220.     whatave = 0;
  221.  
  222.     lseek(kmem, (long) avenrun[0].n_value, 0);
  223.     read(kmem, avg, sizeof (avg));
  224.     
  225.     returnave = avg[whatave] * 100;
  226. /* Now we have the load average to 2 floating point accuracy * 100
  227.  * However, we want to return it with 1 point accuracy that is correctly
  228.  * rounded up or down.  So we divide it by 10 and see what the
  229.  * remainder is and do the rounding (for the integer).
  230.  */
  231.     if(returnave % 10 >= 5)    /* Round up */
  232.     returnave = returnave / 10 + 1;
  233.     else returnave = returnave / 10;
  234.  
  235.     if(returnave >= 250)    /* We cannot return with a number > 255 */
  236.     returnave = 250;    /* and 255 = -1, 254 = -2   */
  237.  
  238.     exit(returnave);        /* Exit with an integer load average */
  239.  
  240. }
  241. SHAR_EOF
  242. if test 1511 -ne "`wc -c < 'getld.c'`"
  243. then
  244.     echo shar: error transmitting "'getld.c'" '(should have been 1511 characters)'
  245. fi
  246. fi
  247. echo shar: extracting "'getload.3'" '(1320 characters)'
  248. if test -f 'getload.3'
  249. then
  250.     echo shar: will not over-write existing file "'getload.3'"
  251. else
  252. cat << \SHAR_EOF > 'getload.3'
  253. .TH GETLOAD 3-local
  254. .SH NAME
  255. getload, ugetload \- load average routines
  256. .SH SYNOPSIS
  257. .nf
  258. .B float getload(whatave)
  259. .B int whatave;
  260. .PP
  261. .B ugetloads(aves)
  262. .B float aves[3];
  263. .fi
  264. .SH DESCRIPTION
  265. These functions allows any program to find what the current
  266. load averages are.
  267. .PP
  268. .I Getload()
  269. returns the 1, 5, or 15 minute load average.  
  270. .I Ugetloads()
  271. puts the 1, 5, and 15 load averages into the array passed to
  272. it.  
  273. .I Getload()
  274. is much faster than
  275. .I ugetloads()
  276. and can be invoked 3 times (to return all 3 load averages) in much
  277. less time than 
  278. .I ugetloads()
  279. can be invoked once.  
  280. .I Getload()
  281. can only return a load average between 0.0 and 25.0, which should
  282. be fine for most applications.
  283. .SH FILES
  284. .B /usr/local/lib/getld \-
  285. The program that actually reads /dev/kmem for 
  286. .I getload()
  287. .br
  288. .B uptime(1) \-
  289. The program that reads /dev/kmem for 
  290. .I ugetload()
  291. .SH DIAGNOSTICS
  292. .I Getload()
  293. returns:
  294. .RS
  295. -99 if the load average is over 25.0
  296. .br
  297. -2  if the program 
  298. .B /usr/local/lib/getld
  299. could not read 
  300. .B /dev/kmem
  301. .br
  302. -1  if 
  303. .B /usr/local/lib/getld
  304. could not read the namelist (\fB/vmunix\fR).
  305. .SH BUGS
  306. The function 
  307. .I getload()
  308. will return a load average of 12.7 if it couldn't execute
  309. the program
  310. .B /usr/local/lib/getld.
  311. .SH AUTHOR
  312. John Bien
  313. .br
  314. UUCP: {ihnp4 | ucbvax | decvax}!trwrb!jsb
  315. .SH DATE
  316. April 1986
  317. SHAR_EOF
  318. if test 1320 -ne "`wc -c < 'getload.3'`"
  319. then
  320.     echo shar: error transmitting "'getload.3'" '(should have been 1320 characters)'
  321. fi
  322. fi
  323. echo shar: extracting "'getload.c'" '(1245 characters)'
  324. if test -f 'getload.c'
  325. then
  326.     echo shar: will not over-write existing file "'getload.c'"
  327. else
  328. cat << \SHAR_EOF > 'getload.c'
  329. /* getload(what)
  330.  * int what;
  331.  *
  332.  * Returns the 1, 5, or 15 minute load average.
  333.  * Call with getload(1), or getload(5), or getload(15).
  334.  * Defaults to getload(1);
  335.  * The program "getld" must be setgid to read /dev/kmem and 
  336.  * located where the execl expects it (/usr/local/lib).
  337.  */
  338. #include <signal.h>
  339. #include "loadstuff.h"
  340.  
  341. float getload(whatave)
  342. int whatave;
  343. {
  344.     int loadav;
  345.     float load;
  346.     char *charav = "1 ";
  347.     int status, pid, w;
  348.  
  349.     if(whatave == 15)
  350.     charav = "15";
  351.     if (whatave == 5)
  352.     charav = "5";
  353.  
  354. /* Now run the getld program, using fork/exec. */
  355.     if ((pid = vfork()) == 0) {
  356. /* This Line should be changed if the program "getld" is not
  357.  * going to be actually called "getld" or wont be in /usr/local/lib
  358.  */
  359.         execl("/usr/local/lib/getld","getld",charav,0);
  360.         _exit(254);
  361.     }
  362.     while ((w = wait(&status)) != pid && w != -1)
  363.         ;
  364.     if (w == -1)
  365.         status = -1;
  366.  
  367.     loadav = (status >> 8);    /* Set loadav to system exit */
  368.  
  369.     load = (float)loadav / 10;  /* Get the correct floating point value */
  370.                 /* that corresponds to the integer */
  371.                 /* exit value we received from getld */
  372.  
  373.     if(loadav == 254) load = NOKMEM;
  374.     if(loadav == 255) load = NONAMELST;
  375.     if(loadav == 250) load = OVERFLOW;
  376.  
  377.     return(load);
  378. }
  379. SHAR_EOF
  380. if test 1245 -ne "`wc -c < 'getload.c'`"
  381. then
  382.     echo shar: error transmitting "'getload.c'" '(should have been 1245 characters)'
  383. fi
  384. fi
  385. echo shar: extracting "'loadstuff.h'" '(87 characters)'
  386. if test -f 'loadstuff.h'
  387. then
  388.     echo shar: will not over-write existing file "'loadstuff.h'"
  389. else
  390. cat << \SHAR_EOF > 'loadstuff.h'
  391. #define NOKMEM -2
  392. #define NONAMELST -1
  393. #define OVERFLOW -99
  394. #define NAMELIST "/vmunix"
  395. SHAR_EOF
  396. if test 87 -ne "`wc -c < 'loadstuff.h'`"
  397. then
  398.     echo shar: error transmitting "'loadstuff.h'" '(should have been 87 characters)'
  399. fi
  400. fi
  401. echo shar: extracting "'u_getloads.c'" '(876 characters)'
  402. if test -f 'u_getloads.c'
  403. then
  404.     echo shar: will not over-write existing file "'u_getloads.c'"
  405. else
  406. cat << \SHAR_EOF > 'u_getloads.c'
  407. /* ugetloads(ls)
  408.  * fload ld[3];
  409.  *
  410.  * Puts the 1, 5, and 15 minute load averages in the float
  411.  * array passed to it.  This program calls upon uptime(1)
  412.  * which could have different ways of printing ie. with bsd4.2
  413.  * "   9:34pm  up 11 hrs,  3 users,  load average: 0.25, 0.22, 0.24  "
  414.  *                                notice the commas -- ^ --- ^.
  415.  * while bsd4.1 does not print commas.  The BSD41 define will 
  416.  * take care of this if that is your system, it defaults to
  417.  * the 4.2 version.
  418.  */
  419.  
  420. #include <stdio.h>
  421.  
  422. FILE *popen();
  423.  
  424. ugetloads(ld)
  425. float ld[3];
  426. {
  427.     FILE *stream;
  428.  
  429.     if((stream = popen("/usr/ucb/uptime","r")) == NULL)
  430.     return(-1);
  431.  
  432. #ifdef BSD41
  433.     fscanf(stream,"%*[^l] load average: %f %f %f", &ld[0],&ld[1],&ld[2]);
  434. #else
  435.     fscanf(stream,"%*[^l] load average: %f, %f, %f", &ld[0],&ld[1],&ld[2]);
  436. #endif BSD41
  437.     pclose(stream);
  438.     return(NULL);
  439. }
  440.  
  441. SHAR_EOF
  442. if test 876 -ne "`wc -c < 'u_getloads.c'`"
  443. then
  444.     echo shar: error transmitting "'u_getloads.c'" '(should have been 876 characters)'
  445. fi
  446. fi
  447. exit 0
  448. #    End of shell archive
  449.